package queue

import (
	"errors"
	"fmt"
)

// 队列: 先进先出 (First In First Out)  FIFO
//允许插入的一端为队尾, 允许删除的一端为队头, 队列有类似于线性表的 各种操作 ,不同的是只能在队尾插入, 只能弹出队头的数据
// 链式队列不存在队列满的情况
/**
	1 插入数据
	2 弹出头部数据
	3 展示所有数据
**/

/*
Object 用于存放任何数据
*/
type Object interface{}

/*
Node 队列的数据
*/
type Node struct {
	data Object
	next *Node
}

/*
Queue 队列
*/
type Queue struct {
	head *Node
	tail *Node
}

/*
InitQueue  队列的初始化
*/
func InitQueue() Queue {
	q := Queue{}
	q.head = nil
	return q
}

/*
Push  向链式队列中插入数据
*/
func (q *Queue) Push(d Object) {
	newNode := &Node{
		data: d,
	}
	// 第一种写法, temp变量作为游标, 遍历到最后一个元素, 缺点是当数据变大之后, 插入会变慢
	// temp := q.head
	// for temp.next != nil {
	// 	temp = temp.next
	// }
	// temp.next = newNode

	//第二种写法, Queue 中增加一个tail 变量, 用于存放最后一个元素, 判断
	if q.Empty() {
		//队列为空的时候, 头和尾都是newNode
		q.head = newNode
		q.tail = newNode
	} else {
		//队列不为空时, 直接操作尾元素即可
		q.tail.next = newNode
		q.tail = newNode
	}

}

/*
Empty 判断链表是否为空
*/
func (q *Queue) Empty() bool {
	if q.head == nil {
		return true
	}
	return false
}

/*
Pop 弹出队头元素
*/
func (q *Queue) Pop() (data Object, err error) {
	if q.Empty() {
		fmt.Println("链表为空无法继续弹出")
		return 0, errors.New("链表为空无法继续弹出")
	}
	head := q.head
	q.head = head.next
	return head.data, nil
}

/*
Show  展示队列所有内容
*/
func (q *Queue) Show() {
	temp := q.head
	for temp != nil {
		fmt.Printf("%v, ", temp.data)
		temp = temp.next
	}
	fmt.Println("展示完所有内容")
}
